package com.bidevalution.business.impl;

import com.bidevalution.business.common.RedisKeys;
import com.bidevalution.business.context.StepStage;
import com.bidevalution.business.enums.VoteAlgorithmEnum;
import com.bidevalution.business.enums.VoteOptionEnum;
import com.bidevalution.business.enums.VoteTypeEnum;
import com.bidevalution.business.exception.CheckException;
import com.bidevalution.business.exception.VoteException;
import com.bidevalution.business.service.*;
import com.bidevalution.business.vote.service.BeAutoVoteConfigService;
import com.bidevalution.business.vote.service.BeExpertVoteService;
import com.bidevalution.business.vote.vi.AutoVoteJobVi;
import com.bidevalution.business.vote.vi.CallStepJobVi;
import com.bidevalution.dao.entity.*;
import com.bidevalution.dao.enums.CheckJobParamsEnum;
import com.bidevalution.dao.enums.VoteLocationEnum;
import com.bidevalution.dao.jdbc.JdbcTemplateSupport;
import com.bidevalution.dao.mapper.*;
import com.bidevalution.dao.utils.StringTools;
import com.bidevalution.service.layout.ColumnHeader;
import com.bidevalution.service.layout.ColumnHeader.ColumnType;
import com.bidevalution.support.context.Constants;
import com.bidevalution.support.context.ResponseObject;
import com.bidevalution.support.context.WebSocketOpTypeEnum;
import com.bidevalution.support.factory.WebSocketService;
import com.bidevalution.support.util.MapUtil;
import com.bidevalution.support.websocket.WebSocketCached;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qtp.core.model.Response;
import com.qtp.core.redis.RedisUtil;
import com.qtp.core.util.GsonUtil;
import com.qtp.core.util.IdsUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.*;
import java.util.Map.Entry;


/**
 * 修改记录
 * 2020-04-17 whc 分数检查增加环节是否已经初始化判断
 * 2020-04-24 whc 添加表决功能
 */
/**
 * @version 1.6
 * @author whc
 * @修改 ZTKP-4025，增加专家确认无误缓存
 */
@Service
public class BeEvalutionOutcomeServiceImpl implements BeEvalutionOutcomeService {
	@Autowired
	private JdbcTemplateSupport jdbcTemplateSupport;
	@Autowired
	private BeSectionExpertInfoService beSectionExpertInfoService;
	@Autowired
	private BeEvalutionOutcomeMapper beEvalutionOutcomeMapper;
	@Autowired
	private WebSocketService webSocketService;
	@Autowired
	private BeSectionExpertProgressService beSectionExpertProgressService;
	@Autowired
	private BeSectionStepMapper beSectionStepMapper;
	@Autowired
	private BeSectionEnterpriseMapper beSectionEnterpriseMapper;
	@Autowired
	private BeSectionExpertProgressMapper beSectionExpertProgressMapper;
	@Autowired
	private BeSectionStepJobService beSectionStepJobService;

	@Autowired
	private BeSectionMethodMapper beSectionMethodMapper;

	@Autowired
	private BeExpertVoteService beExpertVoteService;

	@Autowired
	private VoteUnitNumService voteUnitNumService;

	@Autowired
	private BeAutoVoteConfigService beAutoVoteService;

	private Logger logger = Logger.getLogger(getClass());
	/**
	 * 所有专家都提交完成的任务锁标识
	 */
	private static String AFTER_EXECUTE_JOB_LOCK = "AFTER_EXECUTE_JOB_LOCK";
	@Override
	@Transactional
	public void save(List<Map<String, Object>> dataList, List<ColumnHeader> columnHeaderList,
					 BeSectionStep beSectionStep, String expertId, String layoutCode, String submitCode, String isFinish,
					 boolean isConfirm, List<BeEvalutionColumn> evalutionColumnList) throws Exception {
		logger.info(beSectionStep.getStepName() + ",保存结果.>>>>>>>>>>>>>" + dataList);
		//【现场bug】3月23日杭州市富阳区场口镇鸿丰精品村建设项目--基础设施配套工程、胥口镇佛鲁村石灰厂标准厂房建设工程、施工简易评标，资格核验废掉了8家，有个专家在独立评审中，废标情况少了3家，其他专家正常
		//【现场bug】3月9日，临安区於潜镇“污水零直排区”一期工程，临安施工简易，合理低价审查环节结束后进入下一个符合性评审时系统卡住，不显示数据，后经开发解决得以继续评审下去，且需要发起重评才能正常显示数据。
		//处理mysql锁表be_evalution_outcome   作者：钱立勇 2020-03-26 11:10::00
		synchronized ((beSectionStep.getSectionId() + "save").intern()) {
			logger.info("进入保存锁：key为:---"+beSectionStep.getSectionId() + "save");
			// 添加专家确认无误到缓存
			if (isConfirm) {
				String key = RedisKeys.ExpertConfirm.name() + beSectionStep.getSeqId() + submitCode;
				int expireSecond = RedisKeys.ExpertConfirm.expireSecond;
				RedisUtil.addValueToMap(key, expertId, Boolean.TRUE.toString());
				RedisUtil.expire(key, expireSecond);
			}

			StringBuilder sqlBuilder;
			Map<String, Object> uniqueMap = Maps.newHashMap();
			List<String> columnCodeList = Lists.newArrayList();
			for (BeEvalutionColumn beEvalutionColumn : evalutionColumnList) {
				columnCodeList.add(beEvalutionColumn.getColumnCode().toLowerCase());
			}
			for (Map<String, Object> dataMap : dataList) {
				dataMap.put("sectionStepId", beSectionStep.getSeqId());
				dataMap.put("expertId", expertId);
				dataMap.put("layoutCode", layoutCode);
				dataMap.put("submitCode", submitCode);
				dataMap.put("sectionStepCode", beSectionStep.getStepCode());
				dataMap.put("sectionId", beSectionStep.getSectionId());
				dataMap.put("isDel", "0");
				dataMap.put("isFinish", isFinish);
				if (StringUtils.isEmpty(dataMap.get("enterprise_id"))) {
					dataMap.put("enterprise_id", "0");
				}
				if (dataMap.get("seqId") == null) {
					RowMapper<BeEvalutionOutcome> rm = BeanPropertyRowMapper.newInstance(BeEvalutionOutcome.class);
					BeEvalutionOutcome beEvalutionOutcome = jdbcTemplateSupport.selectForObject(
							"select seq_id from be_evalution_outcome where section_id=:sectionId and section_step_id=:sectionStepId and expert_id=:expertId and enterprise_id=:enterpriseId and layout_code=:layoutCode and is_del=:isDel limit 1",
							MapUtil.create().putValue("sectionId", beSectionStep.getSectionId())
									.putValue("sectionStepId", beSectionStep.getSeqId()).putValue("expertId", expertId)
									.putValue("enterpriseId", dataMap.get("enterprise_id"))
									.putValue("layoutCode", layoutCode).putValue("isDel", Constants.ZERO).getMap(),
							rm);
					if (beEvalutionOutcome != null) {
						uniqueMap.put("seqId", beEvalutionOutcome.getSeqId());
					}
				} else {
					RowMapper<BeEvalutionOutcome> rm = BeanPropertyRowMapper.newInstance(BeEvalutionOutcome.class);
					BeEvalutionOutcome beEvalutionOutcome = jdbcTemplateSupport.selectForObject(
							"select seq_id from be_evalution_outcome where seq_id=:seqId",
							MapUtil.create().putValue("seqId", dataMap.get("seqId")).getMap(), rm);
					if (beEvalutionOutcome != null) {
						uniqueMap.put("seqId", beEvalutionOutcome.getSeqId());
					}
				}
				if (uniqueMap.isEmpty()) {
					sqlBuilder = new StringBuilder("insert into be_evalution_outcome(");
					sqlBuilder.append("seq_id").append(",").append("section_step_id").append(",").append("expert_id")
							.append(",").append("layout_code").append(",").append("submit_code").append(",")
							.append("section_step_code").append(",").append("section_id").append(",").append("is_del")
							.append(",").append("unpassed_reason").append(",").append("is_finish").append(",");
					;
					for (ColumnHeader columnHeader : columnHeaderList) {
						if (columnCodeList.contains(columnHeader.getCode().toLowerCase())) {
							sqlBuilder.append(columnHeader.getCode().toLowerCase()).append(",");
						}
					}
					sqlBuilder.append("create_time").append(",").append("update_time").append(")values(").append("'")
							.append(dataMap.get("seqId") == null ? IdsUtil.uuid() : dataMap.get("seqId")).append("',")
							.append(":sectionStepId").append(",").append(":expertId").append(",").append(":layoutCode")
							.append(",").append(":submitCode").append(",").append(":sectionStepCode").append(",")
							.append(":sectionId").append(",").append(":isDel").append(",").append(":unpassedReason")
							.append(",").append(":isFinish").append(",");
					for (ColumnHeader columnHeader : columnHeaderList) {
						if (columnCodeList.contains(columnHeader.getCode().toLowerCase())) {
							sqlBuilder.append(":").append(columnHeader.getCode()).append(",");
						}
					}
					sqlBuilder.append("now()").append(",").append("now()").append(")");

					dataMap.put("unpassedReason", getUnpassedReason(beSectionStep, columnHeaderList, dataMap));
					//行计算
//				beSectionStepJobService.callRowJob(beSectionStep.getSeqId(), submitCode,expertId,layoutCode,StepStage.Between,uniqueMap);
//
					jdbcTemplateSupport.insert(sqlBuilder.toString(), dataMap);
				} else {
					sqlBuilder = new StringBuilder("update be_evalution_outcome set ");
					for (ColumnHeader columnHeader : columnHeaderList) {
						if (columnCodeList.contains(columnHeader.getCode().toLowerCase())) {
							sqlBuilder.append(
									columnHeader.getCode().toLowerCase() + "=:" + columnHeader.getCode().toLowerCase())
									.append(",");
						}
					}
					sqlBuilder.append("unpassed_reason=:unpassedReason").append(",");
					sqlBuilder.append("update_time=:updateTime").append(",").append("is_finish=:isFinish").append(" where seq_id=:seqId");
					for (ColumnHeader columnHeader : columnHeaderList) {
						for (Entry<String, Object> entry : dataMap.entrySet()) {
							if (entry.getKey().toLowerCase().equals(columnHeader.getCode().toLowerCase())
									&& columnCodeList.contains(columnHeader.getCode().toLowerCase())) {
								uniqueMap.put(entry.getKey().toLowerCase(), entry.getValue());
								break;
							}
						}
					}
					uniqueMap.put("updateTime", new Date());
					uniqueMap.put("isFinish", isFinish);
					uniqueMap.put("unpassedReason", getUnpassedReason(beSectionStep, columnHeaderList, dataMap));
					//行计算
//				beSectionStepJobService.callRowJob(beSectionStep.getSeqId(), submitCode,expertId,layoutCode,StepStage.Between,uniqueMap);
					jdbcTemplateSupport.update(sqlBuilder.toString(), uniqueMap);
				}
			}

			/**************评审过程中调用事件***************************/
			CallStepJobVi callStepJobVi = new CallStepJobVi(beSectionStep.getSeqId(), layoutCode, submitCode, expertId, isConfirm);
			//先执行环节关联的所有子节点的提前计算任务
			beSectionStepJobService.callStepJob(callStepJobVi, StepStage.Between);

			// 通知其他人员
			if (Constants.STR_YES.equals(isFinish)) {
				beSectionStepJobService.callStepJobBySumbit(callStepJobVi);
				// 一个专家完成提交，则通知其他专家
				for (BeSectionExpertInfo sectionExpertInfo : beSectionExpertInfoService
						.getAllListBySectionId(beSectionStep.getSectionId())) {

					logger.info(sectionExpertInfo.getSeqId() + ":" + beSectionStep.getStepCode() + ",发送websocket:"
							+ WebSocketCached.getExpertChannelContextMap().get(sectionExpertInfo.getSeqId()));
					// 发送websocket消息
					if (WebSocketCached.getExpertChannelContextMap().get(sectionExpertInfo.getSeqId()) != null) {
						List<String[]> md5ByIdCards = beSectionExpertInfoService.findMd5ByLoginNames(beSectionStep.getSectionId());
						webSocketService.send(
								WebSocketCached.getExpertChannelContextMap().get(sectionExpertInfo.getSeqId()),
								new ResponseObject(WebSocketOpTypeEnum.EXPERT_FINISH).setMsg(expertId).setTodoList(md5ByIdCards));
					}
				}
			}
		}
	}

	private void resetUnFinishState(List<String> experts, BeSectionStep beSectionStep) {
		for (String expertId: experts) {
			//更新当前所有子节点环节完成状态
			BeSectionExpertProgress beSectionExpertProgress = beSectionExpertProgressService
					.selectByKey(beSectionStep.getSeqId(), expertId);
			beSectionExpertProgress.setIsFinish(Constants.IS_FINISH);
			beSectionExpertProgressService.update(beSectionExpertProgress);
			for (BeSectionStep sectionStep : beSectionStepMapper.getAllChildSectionStep(beSectionStep.getSectionId(),
					beSectionStep.getStepCode())) {
				beSectionExpertProgress = beSectionExpertProgressService.selectByKey(sectionStep.getSeqId(), expertId);
				beSectionExpertProgress.setIsFinish(Constants.IS_FINISH);
				beSectionExpertProgressService.update(beSectionExpertProgress);
			}
		}

	}


	public String getUnpassedReason(BeSectionStep beSectionStep, List<ColumnHeader> columnHeaderList,
									Map<String, Object> dataMap) {
		String enterpriseId = dataMap.get("enterprise_id") == null ? "" : dataMap.get("enterprise_id").toString();
		BeSectionEnterprise beSectionEnterprise = beSectionEnterpriseMapper.selectByPrimaryKey(enterpriseId);
		if (beSectionEnterprise != null) {
			StringBuilder stringBuilder = new StringBuilder();
			StringBuilder itemBuilder = new StringBuilder();
			for (ColumnHeader columnHeader : columnHeaderList) {
				if (ColumnType.SELECT.getCode().equals(columnHeader.getColumnType()) && "1".equals(columnHeader.getRestrictTip())) {
					if ("0".equals(dataMap.get(columnHeader.getCode()))) {
						itemBuilder.append("【" + columnHeader.getName() + "】未通过评审；<br>");
					}
				}
			}
			if(itemBuilder.length()>0) {
				stringBuilder.append("在【" + beSectionStep.getStepName() + "】中以下评审项:").append(itemBuilder);
			}
			return stringBuilder.toString();
		}
		return "";
	}

	/**
	 * 查询标段环节数据是否存在
	 *
	 * @param sectionStepId 标段环节id
	 * @param expertId      专家id
	 * @param layoutCode    布局代码
	 * @return
	 */
	@Override
	public int selectCount(String sectionStepId, String expertId, String layoutCode) {
		return beEvalutionOutcomeMapper.selectCount(sectionStepId, expertId, layoutCode);
	}

	@Override
	public void deleteBySectionId(String sectionId) {
		beEvalutionOutcomeMapper.deleteBySectionId(sectionId);
	}

	@Override
	public List<BeEvalutionOutcome> findBeEvalutionOutcomes(BeEvalutionOutcome beEvalutionOutcome) {
		return beEvalutionOutcomeMapper.findBeEvalutionOutcomes(beEvalutionOutcome);
	}

	@Override
	public List<BeEvalutionOutcomeVo> findC1IsNullByJiShu(BeEvalutionOutcome beEvalutionOutcome) {
		List<BeEvalutionC1IsNullVo> reviewDetails = beEvalutionOutcomeMapper.reviewdetailsByJiShu(beEvalutionOutcome);

		return checkedC1IsNull(beEvalutionOutcome, reviewDetails);
	}

	@Override
	public int updateSyncResult(String sectionId, String sectionStepId, String expertId) throws Exception {
		return beEvalutionOutcomeMapper.updateSyncResult(sectionId, sectionStepId, expertId);
	}

//	public int insertSyncResult(String sectionId, String sectionStepId, String submitCode) throws Exception {
//		return beEvalutionOutcomeMapper.insertSyncResult(sectionId, sectionStepId, submitCode);
//	}

	@Override
	public int insertSyncResult(String sectionId, String sectionStepId, String expertId) throws Exception {
		return beEvalutionOutcomeMapper.insertSyncResult(sectionId, sectionStepId, expertId);
	}


	@Override
	public void updateResult(VoteParams voteParams) {
		beEvalutionOutcomeMapper.updateResult(voteParams);
	}

	@Override
	public void updateChildrenResult(VoteParams voteParams) {
		beEvalutionOutcomeMapper.updateChildrenResult(voteParams);
	}

	@Override
	public void callProcedure(String procedureName, String sectionId, String sectionStepId, String submitCode, String layoutCode, String expertId) {
		beEvalutionOutcomeMapper.callProcedure(procedureName, sectionId, sectionStepId, submitCode, layoutCode, expertId);
	}

	@Override
	public List<BeEvalutionOutcome> findBeEvalutionOutcomeByEnterprise(String sectionId, String sectionStepId){
		return beEvalutionOutcomeMapper.findBeEvalutionOutcomeByEnterprise(sectionId, sectionStepId);
	}

	@Override
	public List<BeEvalutionOutcomeVo> findC1IsNullByZiXin(BeEvalutionOutcome beEvalutionOutcome) {
		List<BeEvalutionC1IsNullVo> reviewDetails = beEvalutionOutcomeMapper.reviewdetailsByZiXin(beEvalutionOutcome);
		beEvalutionOutcome.setIsBidHide(1);
		return checkedC1IsNull(beEvalutionOutcome, reviewDetails);
	}

	private List<BeEvalutionOutcomeVo> checkedC1IsNull(BeEvalutionOutcome beEvalutionOutcome,List<BeEvalutionC1IsNullVo> reviewDetails) {
		Map<String, BeEvalutionOutcomeVo> reviewMap = new LinkedHashMap<>();
		// 获取 isdel 为0 的
		beEvalutionOutcome.setIsDel(Constants.STR_NO);
		beEvalutionOutcome.setSubmitCode(null);
		List<BeEvalutionOutcome> beEvalutionOutcomes = beEvalutionOutcomeMapper.findBeEvalutionOutcomes(beEvalutionOutcome);
		// list to Map
		Map<String, BeEvalutionOutcome> resultMap = new HashMap<>();
		for (BeEvalutionOutcome item: beEvalutionOutcomes) {
			resultMap.put(item.getM1() + item.getEnterpriseId(), item);
		}

		for (BeEvalutionC1IsNullVo item: reviewDetails) {
			BeEvalutionOutcome outcome = resultMap.get(item.getM1()+item.getEnterpriseId());
			// 判断没评审项目
			if (outcome == null || StringUtils.isEmpty(outcome.getC1())) {
				// 添加到 reviewMap
				String name = beEvalutionOutcome.getIsBidHide() == 2 ? item.getHideNumber() :item.getEnterpriseName();
				BeEvalutionOutcomeVo beEvalutionOutcomeVo = reviewMap.get(name);
				if (beEvalutionOutcomeVo == null) {
					beEvalutionOutcomeVo = new BeEvalutionOutcomeVo();
				}

				beEvalutionOutcomeVo.addContent(name, item.getTechName());
				reviewMap.put(name, beEvalutionOutcomeVo);
			}
		}

		return new ArrayList<>(reviewMap.values());
	}

}
